package com.chevic.servlet;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Random;


/**
 * @类型名称: ImageCheck
 * @功能说明:随机生成校验图片
 * @修改说明：把验证码存放session的键提到类前，方便查看
 */
public class ImageCheck extends HttpServlet {
	private final String SESSIONKEY = "CHECKIMAGE_CODE";
	
	/**
     * 验证码长度（默认4个验证码的长度）  
     */ 
    int length = 4;  

    /**
     * 验证码字体大小（为了显示扭曲效果，默认50像素，可以自行修改）  
     */ 
    int fontSize = 50;  

    /**
     * 边框补（默认2像素）  
     */ 
    int padding = 2;  

    /**
     * 是否输出燥点（默认输出）  
     */ 
    boolean chaos = true;  

    /**
     * 输出燥点的颜色（默认灰色）  
     */ 
    Color chaosColor = Color.lightGray; 
	
	/**
	 * 自定义字体数组
	 */
	String[] fonts = { "Arial", "Georgia", "Times New Roman" };

	/**
	 * 自定义背景色（默认白色）
	 */
	Color backgroundColor = Color.white;

	/**
	 * 产生波形滤镜效果
	 */
	private final double PI = 3.1415926535897932384626433832799;// 此值越大，扭曲程度越大

	private BufferedImage image;

	public int getLength() {
		return length;

	}

	public void setLength(int length) {
		this.length = length;
	}

	public int getFontSize() {
		return fontSize;
	}

	public void setFontSize(int fontSize) {
		this.fontSize = fontSize;
	}

	public int getPadding() {
		return padding;
	}

	public void setPadding(int padding) {
		this.padding = padding;
	}

	public boolean isChaos() {
		return chaos;
	}

	public void setChaos(boolean chaos) {
		this.chaos = chaos;
	}

	public Color getChaosColor() {
		return chaosColor;
	}

	public void setChaosColor(Color chaosColor) {
		this.chaosColor = chaosColor;
	}

	public Color getBackgroundColor() {
		return backgroundColor;
	}

	public void setBackgroundColor(Color backgroundColor) {
		this.backgroundColor = backgroundColor;
	}

	public String[] getFonts() {
		return fonts;
	}

	public void setFonts(String[] fonts) {
		this.fonts = fonts;
	}

    
	public void init() throws ServletException {
		super.init();
	}

	// 定义图形验证码中绘制字符的字体
	private final Font mFont = new Font("Arial Black", Font.PLAIN, 12);
	// 定义图形验证码的大小
	private final int IMG_WIDTH = 60;
	private final int IMG_HEIGTH = 20;

	// 定义一个获取随机颜色的方法
	private Color getRandColor(int fc, int bc) {
		Random random = new Random();
		if (fc > 255)
			fc = 255;
		if (bc > 255)
			bc = 255;
		int r = fc + random.nextInt(bc - fc);
		int g = fc + random.nextInt(bc - fc);
		int b = fc + random.nextInt(bc - fc);
		// 得到随机颜色
		return new Color(r, g, b);
	}

	// 重写service方法，生成对客户端的响应
	public void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//设置禁止缓存   
        response.setHeader("Pragma","No-cache");   
        response.setHeader("Cache-Control","no-cache");   
        response.setDateHeader("Expires", 0);   
        response.setContentType("image/jpeg"); 
        String sRand = setImage();
        
        //获取HttpSesssion对象   
        HttpSession session = request.getSession(true);   
        session.setAttribute(SESSIONKEY , sRand);  
        ImageIO.write(image, "JPEG", response.getOutputStream());  
	}

	private String setImage() {
		int fWidth = this.fontSize + this.padding;  
        
        //图象的宽度  
        int imageWidth = (int) (4 * fWidth) + 4 + this.padding * 2;  
        //图象的高度  
        int imageHeight = this.fontSize * 2 ;  
        
		image = new BufferedImage(imageWidth, imageHeight,  
                BufferedImage.TYPE_INT_RGB);
		Graphics g = image.getGraphics();
		Random random = new Random();

		g.setColor(getRandColor(200, 250));
		// 填充背景色
		g.fillRect(1, 1,image.getWidth() - 1, image.getHeight() - 1);
		// 为图形验证码绘制边框
		g.setColor(new Color(102, 102, 102));
		g.drawRect(0, 0, image.getWidth() - 1, image.getHeight() - 1);
		g.setColor(getRandColor(160, 200));
		// 生成随机干扰线
		// 给背景添加随机生成的燥点,使图象中的认证码不易被其它程序探测到  
        if (this.chaos) {  
                int c = this.length * 10;  
                for (int i = 0; i < c; i++) {  
                        int x = random.nextInt(image.getWidth());  
                        int y = random.nextInt(image.getHeight());  
                        g.setColor(this.chaosColor);// 设置燥点的颜色  
                        g.drawRect(x, y, 1, 1);// 生成燥点  
                        g.drawLine(x, y, 1, 1);//生成干扰线  
                }  
        } 
		// 用于保存系统生成的随机字符串
		String sRand = "";

		for (int i = 0; i < 4; i++) {
			String tmp = getRandomChar();
			tmp = tmp.toUpperCase();
			int top = (imageHeight + 4*2) / 2;  
            if (i % 2 != 1) {  
                    top = top - 4;  
            }  
            int left = i * fWidth+4;
			 //设置字体属性  
            int findex = random.nextInt(this.fonts.length);  
            Font font = new Font(fonts[findex], Font.PLAIN, this.fontSize);  
            g.setFont(font);
			sRand += tmp;
			// 获取随机颜色
			g.setColor(this.getRandColor(0+ i, 150 - i)); 
			// 在图片上绘制系统生成的随机字符
			g.drawString(tmp, left, top);
		}
		

		g.dispose();
		
		// 产生波形  
		image = TwistImage(image, true, 8, 4);  
		// 向输出流中输出图片
		return sRand;
	}

	// 定义获取随机字符串方法
	private String getRandomChar() {
		// 生成一个0、1、2的随机数字
		int rand = (int) Math.round(Math.random() * 2);
		long itmp = 0;
		char ctmp = '\u0000';
		switch (rand) {
		// 生成大写字母
		case 1:
			itmp = Math.round(Math.random() * 25 + 65);
			ctmp = (char) itmp;
			return String.valueOf(ctmp);
			// 生成小写字母
		case 2:
			itmp = Math.round(Math.random() * 25 + 97);
			ctmp = (char) itmp;
			return String.valueOf(ctmp);
			// 生成数字
		default:
			itmp = Math.round(Math.random() * 9);
			return itmp + "";
		}
	}
    /**
     * 正弦曲线Wave扭曲图片  
     *   
     * @param srcBi  
     *            图片路径  
     * @param bXDir  
     *            如果扭曲则选择为true  
     * @param dMultValue  
     *            波形的幅度倍数，越大扭曲的程序越高，一般为3  
     * @param dPhase  
     *            波形的起始相位，取值区间（0-2＊PI）  
     * @return  
     */ 
    private BufferedImage TwistImage(BufferedImage srcBi, boolean bXDir,  
                    double dMultValue, double dPhase) {  
            // 在内存中创建图象  
            BufferedImage destBi = new BufferedImage(srcBi.getWidth(), srcBi  
                            .getHeight(), BufferedImage.TYPE_INT_RGB);  

            // 获取图形上下文  
            Graphics graphics = destBi.getGraphics();  
              
            // 将位图填充背景色，默认为黑色  
            graphics.setColor(this.backgroundColor);  
            graphics.fillRect(0, 0, destBi.getWidth(), destBi.getHeight());  


            // 图象生效  
            graphics.dispose();  

            double dBaseAxisLen = bXDir ? (double) destBi.getHeight()  
                            : (double) destBi.getWidth();  

            for (int i = 0; i < destBi.getWidth(); i++) {  
                    for (int j = 0; j < destBi.getHeight(); j++) {  
                            double dx = 0;  
                            dx = bXDir ? (PI * (double) j) / dBaseAxisLen  
                                            : (PI * (double) i) / dBaseAxisLen;  
                            dx += dPhase;  
                            double dy = Math.sin(dx);  

                            // 取得当前点的颜色  
                            int nOldX = 0, nOldY = 0;  
                            nOldX = bXDir ? i + (int) (dy * dMultValue) : i;  
                            nOldY = bXDir ? j : j + (int) (dy * dMultValue);  
                            int rgb = srcBi.getRGB(i, j);  
                            if (nOldX >= 0 && nOldX < destBi.getWidth() && nOldY >= 0 
                                            && nOldY < destBi.getHeight()) {  
                                    destBi.setRGB(nOldX, nOldY, rgb);  
                            }  

                    }  
            }  

            return destBi;  
    }  
	/*
	 * public void outputImage() { try { ImageIO.write(image, "JPEG", new
	 * File("test.jpg")); } catch (IOException e) { // TODO Auto-generated catch
	 * block e.printStackTrace(); } }
	 * 
	 * public static void main(String[] args) throws SQLException { //
	 * ImageCheck ic = new ImageCheck(); // ic.outputImage(); }
	 */

}